#include "EpilFunctionNameParser.h"
#include "EpilParserException.h"
#include "EpilIdentifierExpressionCode.h"
#include "EpilFieldParser.h"
#include "EpilFunctionNameCode.h"


EpilFunctionNameParser::EpilFunctionNameParser( EpilTokenStream & tokens )
: EpilSyntaxParserBase( tokens )
{
}


void EpilFunctionNameParser::Parse()
{
	// funcname -> NAME {field} [`:' NAME]
	if( this->GetTokens().GetCurrentToken().type != ETT_Identifier )
	{
		throw EpilParserException( t("Identifier expected."), this->GetTokens().GetCurrentToken().location );
	}
	const EpilToken & headToken = this->GetTokens().GetCurrentToken();
	tstring headName = this->GetTokens().GetCurrentToken().text;
	this->GetTokens().MoveToNext();

	list<tstring> fields;
	while( this->GetTokens().GetCurrentToken().type == ETT_OpTableMemberAccess )
	{
		EpilFieldParser fieldParser( this->GetTokens() );
		fieldParser.Parse();
		fields.push_back( fieldParser.GetFieldName() );
	}

	tstring method = t("");
	if( this->GetTokens().GetCurrentToken().type == ETT_OpObjectMemberAccess )
	{
		EpilFieldParser fieldParser( this->GetTokens() );
		fieldParser.Parse();
		method = fieldParser.GetFieldName();
	}

	if( fields.empty() )
	{
		if( method.empty() )
		{
			EpilFunctionNameCode * nameCode = new EpilFunctionNameCode( headToken.location );
			nameCode->SetName( headName );
			nameCode->SetMethod( false );
			m_functionName = nameCode;
		}
		else
		{
			EpilFunctionNameCode * nameCode = new EpilFunctionNameCode( headToken.location );
			nameCode->GetTableNames().push_back( headName );
			nameCode->SetName( method );
			nameCode->SetMethod( true );
			m_functionName = nameCode;
		}
	}
	else
	{
		if( method.empty() )
		{
			EpilFunctionNameCode * nameCode = new EpilFunctionNameCode( headToken.location );

			nameCode->GetTableNames().push_back( headName );
			list<tstring>::iterator itLast = fields.end();
			--itLast;
			copy( fields.begin(), itLast, back_inserter( nameCode->GetTableNames() ) );

			nameCode->SetName( *itLast );
			nameCode->SetMethod( false );

			m_functionName = nameCode;
		}
		else
		{
			EpilFunctionNameCode * nameCode = new EpilFunctionNameCode( headToken.location );

			nameCode->GetTableNames().push_back( headName );
			copy( fields.begin(), fields.end(), back_inserter( nameCode->GetTableNames() ) );

			nameCode->SetName( method );
			nameCode->SetMethod( true );

			m_functionName = nameCode;
		}
	}
}